package com.powernode.ssm.springAnalysis.a05;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.*;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.type.MethodMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.util.Set;

/**
 * 自定义的bean后处理器，模仿spring扫描@Bean注解
 */

public class AtBeanPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        try {
            CachingMetadataReaderFactory factory = new CachingMetadataReaderFactory();
            //只解析class文件不加载，效率比反射高，拿到Config文件信息
            MetadataReader reader = factory.getMetadataReader(new ClassPathResource("com/powernode/ssm/springAnalysis/a05/Config.class"));
            //拿到config文件中关于@Bean注解的方法的信息
            Set<MethodMetadata> methods = reader.getAnnotationMetadata().getAnnotatedMethods(Bean.class.getName());
            for (MethodMetadata method : methods) {
                System.out.println(method);
                //获取initMethod的值
                String initMethod = method.getAnnotationAttributes(Bean.class.getName()).get("initMethod").toString();

                //定义BeanDefinition构造器
                BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
                //设置config配置类的工厂方法
                builder.setFactoryMethodOnBean(method.getMethodName(), "config");
                //工厂类自动装配基本采用AUTOWIRE_CONSTRUCTOR模式
                //解决DataSource dataSource作为参数传入的问题
                builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
                if (!initMethod.isEmpty()) {
                    builder.setInitMethodName(initMethod);
                }
                AbstractBeanDefinition bd = builder.getBeanDefinition();
                if (configurableListableBeanFactory instanceof DefaultListableBeanFactory){
                    DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory)configurableListableBeanFactory;
                    beanFactory.registerBeanDefinition(method.getMethodName(), bd);
                }

            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanFactory) throws BeansException {
    }
}
